/**
 * draggable - Class allows to make any element draggable
 *
 * Written by
 * Egor Khmelev (hmelyoff@gmail.com)
 *
 * Licensed under the MIT (MIT-LICENSE.txt).
 *
 * @author Egor Khmelev
 * @version 0.1.0-BETA ($Id$)
 *
 **/

(function ($) {

    function Draggable() {
        this._init.apply(this, arguments);
    };

    Draggable.prototype.oninit = function () {

    };

    Draggable.prototype.events = function () {

    };

    Draggable.prototype.onmousedown = function () {
        this.ptr.css({position: "absolute"});
    };

    Draggable.prototype.onmousemove = function (evt, x, y) {
        this.ptr.css({left: x, top: y});
    };

    Draggable.prototype.onmouseup = function () {

    };

    Draggable.prototype.isDefault = {
        drag: false,
        clicked: false,
        toclick: true,
        mouseup: false
    };

    Draggable.prototype._init = function () {
        if (arguments.length > 0) {
            this.ptr = $(arguments[0]);
            this.outer = $(".draggable-outer");

            this.is = {};
            $.extend(this.is, this.isDefault);

            var _offset = this.ptr.offset();
            this.d = {
                left: _offset.left,
                top: _offset.top,
                width: this.ptr.width(),
                height: this.ptr.height()
            };

            this.oninit.apply(this, arguments);

            this._events();
        }
    };

    Draggable.prototype._getPageCoords = function (event) {
        if (event.targetTouches && event.targetTouches[0]) {
            return {x: event.targetTouches[0].pageX, y: event.targetTouches[0].pageY};
        } else
            return {x: event.pageX, y: event.pageY};
    };

    Draggable.prototype._bindEvent = function (ptr, eventType, handler) {
        var self = this;

        if (this.supportTouches_)
            ptr.get(0).addEventListener(this.events_[eventType], handler, false);

        else
            ptr.bind(this.events_[eventType], handler);
    };

    Draggable.prototype._events = function () {
        var self = this;

        this.supportTouches_ = 'ontouchend' in document;
        this.events_ = {
            "click": this.supportTouches_ ? "touchstart" : "click",
            "down": this.supportTouches_ ? "touchstart" : "mousedown",
            "move": this.supportTouches_ ? "touchmove" : "mousemove",
            "up": this.supportTouches_ ? "touchend" : "mouseup"
        };

        this._bindEvent($(document), "move", function (event) {
            if (self.is.drag) {
                event.stopPropagation();
                event.preventDefault();
                self._mousemove(event);
            }
        });
        this._bindEvent($(document), "down", function (event) {
            if (self.is.drag) {
                event.stopPropagation();
                event.preventDefault();
            }
        });
        this._bindEvent($(document), "up", function (event) {
            self._mouseup(event);
        });

        this._bindEvent(this.ptr, "down", function (event) {
            self._mousedown(event);
            return false;
        });
        this._bindEvent(this.ptr, "up", function (event) {
            self._mouseup(event);
        });

        this.ptr.find("a")
            .click(function () {
                self.is.clicked = true;

                if (!self.is.toclick) {
                    self.is.toclick = true;
                    return false;
                }
            })
            .mousedown(function (event) {
                self._mousedown(event);
                return false;
            });

        this.events();
    };

    Draggable.prototype._mousedown = function (evt) {
        this.is.drag = true;
        this.is.clicked = false;
        this.is.mouseup = false;

        var _offset = this.ptr.offset();
        var coords = this._getPageCoords(evt);
        this.cx = coords.x - _offset.left;
        this.cy = coords.y - _offset.top;

        $.extend(this.d, {
            left: _offset.left,
            top: _offset.top,
            width: this.ptr.width(),
            height: this.ptr.height()
        });

        if (this.outer && this.outer.get(0)) {
            this.outer.css({height: Math.max(this.outer.height(), $(document.body).height()), overflow: "hidden"});
        }

        this.onmousedown(evt);
    };

    Draggable.prototype._mousemove = function (evt) {
        this.is.toclick = false;
        var coords = this._getPageCoords(evt);
        this.onmousemove(evt, coords.x - this.cx, coords.y - this.cy);
    };

    Draggable.prototype._mouseup = function (evt) {
        var oThis = this;

        if (this.is.drag) {
            this.is.drag = false;

            if (this.outer && this.outer.get(0)) {

                if ($.browser.mozilla) {
                    this.outer.css({overflow: "hidden"});
                } else {
                    this.outer.css({overflow: "visible"});
                }

                if ($.browser.msie && $.browser.version == '6.0') {
                    this.outer.css({height: "100%"});
                } else {
                    this.outer.css({height: "auto"});
                }
            }

            this.onmouseup(evt);
        }
    };

    window.Draggable = Draggable;

})(jQuery);
